﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Text.RegularExpressions;
using System.Collections.Generic;


namespace Galoap
{

    /// <summary>
    ///  Implementation of ParserInterrogator
    /// </summary>
    public class MyParserInterrogator : ParserInterrogator
    {
        /// <summary>
        /// the site of Tanl
        /// </summary>
        public override string site { get; set; }

        /// <summary>
        /// the phrase to ask
        /// </summary>
        public override string phrase { get; set; }

        /// <summary>
        /// the constructor
        /// </summary>
        public MyParserInterrogator(string phrase)
        {
            this.site = "http://paleo.di.unipi.it/parse";
            this.phrase = phrase;
        }

        /// <summary>
        /// the constructor
        /// </summary>
        public MyParserInterrogator()
        {
            this.site = "http://paleo.di.unipi.it/parse";
            this.phrase = "";
        }
        /// <summary>
        /// Ask to Tanl to make the part-of-speech for the phrase 'phrase'
        /// </summary>
        /// <returns>a list of triple ontology of type part-of-speech for that phrase</returns>
        public override Ontology[] PartOfSpeechRequest()
        {
            return TanlRequest(0, 0)[0];
        }

        /// <summary>
        /// Ask Tanl to make the first semantic tree of the phrase phrase
        /// </summary>
        /// <returns>the semantic tree of the phrase phrase of index i</returns>
        public override Tree SemanticTreeRequest()
        {
            return CreateSemanticTree(TanlRequest(0, 1)[0], "0", null, 0)[0];
        }

        /// <summary>
        /// Ask Tanl to make the first semantic tree of the phrase phrase
        /// </summary>
        /// <returns>list of ontology representing the first semantic tree of the phrase</returns>
        public override Ontology[] SemanticOntologyTreeRequest()
        {
            return TanlRequest(0, 1)[0];
        }


        /// <summary>
        /// Ask Tanl to make the i-th semantic tree of the phrase phrase
        /// </summary>
        /// <param name="index">the index of the table for this phrase which we want from the parser</param>
        /// <returns>list of ontology representing the semantic tree of the phrase of index i</returns>
        public override Ontology[] SemanticOntologyTreeRequest(int index)
        {
            return TanlRequest(index, 1)[index];
        }

        /// <summary>
        /// Ask Tanl to make the i-th semantic tree of the phrase phrase
        /// </summary>
        /// <param name="index">the index of the table for this phrase which we want from the parser</param>
        /// <returns>the semantic tree of the phrase phrase of index i</returns>
        public override Tree SemanticTreeRequest(int index)
        {
            return CreateSemanticTree(TanlRequest(index, 1)[index], "0", null, 0)[0];
        }

        /// <summary>
        /// Ask Tanl to give the first num semantic tree of the phrase phrase
        /// </summary>
        /// <param name="num">the number of tables we want</param>
        /// <returns>list of tree of the phrase</returns>
        public override Tree[] SemanticTreesRequest(int num)
        {
            Ontology[][] o = TanlRequest(num-1, 1);
            Tree[] t = new Tree[num];
            for (int i = 0; i < num; i++)
                t[i] = CreateSemanticTree(o[i], "0", null, 0)[0];
            return t;
        }



        /// <summary>
        /// Ask Tanl to give the first num semantic tree of the phrase phrase
        /// </summary>
        /// <param name="phrase">the phrase to ask</param>
        /// <param name="num">the number of tables we want</param>
        /// <returns>list of ontology representing the semantic tree of the phrase</returns>
        public override Ontology[][] SemanticOntologyTreesRequest(int num)
        {
            return TanlRequest(num-1, 1);
        }

        /// <summary>
        /// ask the parser to give the table for the string phrase of index i
        /// return the list of triple <subject, predicate, object> of a given type
        /// </summary>
        /// <param name="i">the num of table for this phrase which we want from the parser</param>
        /// <param name="type">the type of the triple we want extract from the table</param>
        ///     0 - part of speech
        ///     1 - semantic tree
        /// <returns> a list of triple ontology for that phrase</returns>
        private Ontology[][] TanlRequest(int i, int type)
        {

            string query = site + "?q=" + System.Web.HttpUtility.UrlEncode(phrase) + "&n=" + i;

            // used to build entire input
            StringBuilder sb = new StringBuilder();

            // used on each read operation
            byte[] buf = new byte[8192];

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(query);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream resStream = response.GetResponseStream();

            string tempString = null;
            int count = 0;

            do
            {
                // fill the buffer with data
                count = resStream.Read(buf, 0, buf.Length);

                // make sure we read some data
                if (count != 0)
                {
                    // translate from bytes to ASCII text
                    tempString = Encoding.ASCII.GetString(buf, 0, count);

                    // continue building the string
                    sb.Append(tempString);
                }
            }
            while (count > 0); // any more data to read?

            response.Close();
            /*
             * REMOVE ME
             * 
            string prova = "1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n1\tPer\tper\tE\tE\t_\t6\tcomp\t_\t_\n2\tfare\tfare\tV\tV\tmod=f\t1\tprep\t_\t_\n3\tun\tun\tR\tRI\tnum=s|gen=m\t4\tdet\t_\t_\n4\talbero\talbero\tS\tS\tnum=s|gen=m\t2\tobj\t_\t_\n5\tci\tci\tP\tPC\tnum=n|gen=n\t6\tcomp\t_\t_\n6\tvuole\tvolere\tV\tV\tnum=s|per=3|mod=i|ten=p\t0\tROOT\t_\t_\n7\tun\tun\tR\tRI\tnum=s|gen=m\t8\tdet\t_\t_\n8\tfiore\tfiore\tS\tS\tnum=s|gen=m\t6\tsubj\t_\t_\n9\t.\t.\tF\tFS\t_\t6\tpunc\t_\t_\n\n";
            Ontology[][] o = this.SplitTables(prova, type);
            return o;*/

            //*************************** REMOVE WHEN TANL METHOD IS READY ***************************
            Ontology[][] o = new Ontology[i + 1][];
            for (int j=0;j<o.Length;j++)
                o[j] = ProcessTable(sb.ToString(), type);
            return o;

            //*************************** SUBSTITUTE WITH THIS WHEN THE TANL METHOD IS READY ***************************
            //return SplitTables(sb.ToString(), type);
        }

        /// <summary>
        ///  construct the list of triple of the given type from the table
        /// </summary>
        /// <param name="table">the table in which we want to extract information</param>
        /// <param name="type">the type of the triple we want extract from the table
        ///     0 - part of speech
        ///     1 - semantic tree
        /// </param>
        /// <returns> a list of triple for that phrase, null if type is not specified</returns>
        private Ontology[] ProcessTable(string table, int type)
        {
            List<Ontology> l = new List<Ontology>();

            string[] lines = Regex.Split(table, "	");

            string[] temp = new string[3];

            int j;

            if (type == 0)
            {
                temp[1] = "is";
                j = 3; //tag
            }
            else if (type == 1)
            {
                temp[1] = "relate";
                j = 6; //relation
            }
            else
                return null; //type not specified

            for (int i = 0; i < lines.Length; i++)
            {
                if ((i % 9) == 1)
                    temp[0] = lines[i];
                else if ((i % 9) == j)
                {
                    temp[2] = lines[i];
                    l.Add(new Ontology(temp[0], temp[1], temp[2]));
                }
            }

            return l.ToArray();
        }

        /// <summary>
        /// Split the string table by \n\n and process each tables
        /// </summary>
        /// <param name="table">the string contentens n table divided by "\n\n"</param>
        /// <param name="type">the type of the triple we want extract from the table 
        ///     0 - part of speech
        ///     1 - semantic tree</param>
        /// <returns>the n list of ontology calculated for the phrase</returns>
        private Ontology[][] SplitTables(string table, int type)
        {

            string[] tables = Regex.Split(table, "\n\n");
            Ontology[][] ont = new Ontology[tables.Length][];
            for (int i = 0; i < tables.Length - 1; i++)
            {
                ont[i] = this.ProcessTable(tables[i], type);
            }
            return ont;
        }

        /// <summary>
        /// This method generate the a Tree from the list of ontology
        /// </summary>
        /// <param name="l">the list of Ontology to convert in Tree</param>
        /// <returns>create a Tree from the list of ontology </returns>
        public override Tree CreateSemanticTree(Ontology[] l)
        {
            return CreateSemanticTree(l, "0", null, 0)[0];
        }

        /// <summary>
        /// This method generate the sub-tree of node related to "index" from a List of Ontology l
        /// </summary>
        /// <param name="l">the list of Ontology to convert in Tree</param>
        /// <param name="index">the index of the node which he referred</param>
        /// <returns>a List of Tree relate to the node index</returns>
        private Tree[] CreateSemanticTree(Ontology[] l, string index, Tree parent, int level)
        {
            int j = 1;
            int child_index = 0;
            List<Tree> child = new List<Tree>();
            level++;
            foreach (Ontology o in l)
            {
                if (o.Object == index)
                {
                    child.Add(new Tree(o, j, parent, level, child_index));
                    child_index++;
                }
                j++;
            }
            foreach (Tree t in child)
                t.Child = CreateSemanticTree(l, t.Index.ToString(), t, level);
            return child.ToArray();
        }

    }
}
